#include "mainwindow.h"
#include "ui_mainwindow.h"



MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    ui->tabWidget->removeTab(0);
    ui->tabWidget->removeTab(0);
    connect(ui->tabWidget, &QTabWidget::tabCloseRequested, this, &MainWindow::onTabCloseRequested);
    connect(ui->actionOpen_File,&QAction::triggered,this,&MainWindow::OpenFile);
    connect(ui->actionNew_File, &QAction::triggered,this,&MainWindow::newTab);
    connect(ui->actionTokens, &QAction::triggered,this,&MainWindow::lexicalAnalysis);
    connect(ui->actionSave_File,&QAction::triggered,this,&MainWindow::saveCurrentTab);
    connect(ui->actionSaveAS_File,&QAction::triggered,this,&MainWindow::saveAsCurrentTab);
    connect(ui->actionOptimize_2,&QAction::triggered,this,&MainWindow::optimize);
    connect(ui->actionQuaternary,&QAction::triggered,this,&MainWindow::quaternary);
    connect(ui->actionsymbol_table,&QAction::triggered,this,&MainWindow::symbolTable);
    connect(ui->actionresult_2,&QAction::triggered,this,&MainWindow::objectCode);

    new QShortcut(QKeySequence::Save, this, SLOT(saveCurrentTab()));
    // ui->menu_3->setProperty("iconStyle",true);
    QPixmap runPixmap(":/icon/icons/run.svg");
    runPixmap = runPixmap.scaled(15, 15, Qt::KeepAspectRatio, Qt::SmoothTransformation);
    // ui->menu_3->setIcon(QIcon(":/icon/icons/run.svg"));

    QString menubarStyle = loadStyleSheet(":/qss/qss/style1.qss");
    ui->menubar->setStyleSheet(menubarStyle);
    QString tabSytle = loadStyleSheet(":/qss/qss/style2.qss");
    ui->tabWidget->setStyleSheet(tabSytle);
    QString tableWidgetStyle = loadStyleSheet(":/qss/qss/style3.qss");
    this->setStyleSheet(tableWidgetStyle);


    runAction = new QAction(QIcon(runPixmap), "运行", this);
    QToolBar *toolBar = addToolBar("运行工具栏");
    toolBar->addAction(runAction);
    //toolBar->setBaseSize(5,5);
    QString toolBarStyle = loadStyleSheet(":/qss/qss/style4.qss");
    toolBar->setStyleSheet(toolBarStyle);
    connect(runAction, &QAction::triggered, this, &MainWindow::onRunActionTriggered);
}

MainWindow::~MainWindow()
{
    delete ui;
}
void MainWindow::OpenFile(){
    QString filepath = QFileDialog::getOpenFileName(
        nullptr,                // 父窗口（可为空）
        "打开文件",              // 对话框标题
        //QDir::homePath(),       // 初始目录（用户主目录）
        QDir::currentPath(),
        "源文件 (*.c);所有文件 (*.*);" // 文件过滤器
        );
    if (filepath.isEmpty()) {
        return;
    }

    QString contect = file.read(filepath);
    newTab();

    normalTab* currentWidget = dynamic_cast<normalTab*>(ui->tabWidget->currentWidget());
    if (!currentWidget) {
        QMessageBox::warning(this, tr("错误"), tr("无法获取当前标签页"));
        return;
    }

    qDebug()<<currentWidget->getIsEdit();
    currentWidget->setFilePath(filepath);
    //updateTabTitle(ui->tabWidget->count()-1);
    QFileInfo fileInfo(filepath);
    // 代码高亮
    QString ext = fileInfo.suffix().toLower();
    new Highlighter(ext, "monokai", currentWidget->getTextEdit()->document());
    currentWidget->getTextEdit()->setText(contect);
    currentWidget->setIsEdit(false);
    // 设置文件名
    this->filename = fileInfo.fileName();
    //currentWidget->setWindowTitle(filename);
    int tabIndex = this->ui->tabWidget->currentIndex();
    ui->tabWidget->setTabText(tabIndex, fileInfo.fileName());

    qDebug()<<currentWidget->getIsEdit();
    // qDebug()<<ui->tabWidget->currentIndex();
}
void MainWindow::newTab(){
    // if (ui->tabWidget->count() < 50){
    //     ui->tabWidget->addTab(new GeistTextEdit, "New File");
    //     ui->tabWidget->setCurrentIndex(ui->tabWidget->count() - 1);
    //     ui->tabWidget->setTabToolTip(ui->tabWidget->currentIndex(), "");
    //     filename = "";

    //     setTabWidth(settings.value("tabWidth", 4).toInt());
    //     currentEditorWidget->setWordWrapMode(QTextOption::NoWrap);
    // }
    if(ui->tabWidget->count()<20){
        normalTab* newTab = new normalTab();
        ui->tabWidget->addTab(newTab,"test.c");
        //ui->tabWidget->addTab()
        new Highlighter("c", "monokai", newTab->getTextEdit()->document());
        //new Highlighter("c", "github", newTab->getTextEdit()->document());
        ui->tabWidget->setCurrentIndex(ui->tabWidget->count()-1);
        setupEditor(newTab->getTextEdit(), ui->tabWidget->count()-1);
        updateTabTitle(ui->tabWidget->count()-1);
    }

}
void MainWindow::onTabCloseRequested(int index){
    normalTab* widget = dynamic_cast<normalTab*>(ui->tabWidget->widget(index));
    //QWidget *widget = ui->tabWidget->widget(index);
    // qDebug()<<ui->tabWidget->currentIndex();
    // qDebug()<<widget->getIsEdit();
    if(widget!=nullptr&&widget->getIsEdit()){
        QMessageBox::StandardButton reply = QMessageBox::question(
            this,
            "Close Tab",
            "Save changes before closing?",
            QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel
            );
        if (reply == QMessageBox::Save) {
            //saveCurrentFile();
            saveCurrentTab();
            ui->tabWidget->removeTab(index);
            delete widget;
        } else if (reply == QMessageBox::Discard) {
            ui->tabWidget->removeTab(index);
            delete widget;
        }
    }else{
        ui->tabWidget->removeTab(index);
        delete widget;
    }
}
// 示例保存函数（需根据实际需求实现）
void MainWindow::saveCurrentFile() {
    normalTab* currentWidget = dynamic_cast<normalTab*>(ui->tabWidget->currentWidget());
    if (auto *textEdit = currentWidget->getTextEdit()) {
        QString content = textEdit->toPlainText();
        QString filePath = QFileDialog::getSaveFileName(this, "Save File");
        if (!filePath.isEmpty()) {
            QFile file(filePath);
            if (file.open(QIODevice::WriteOnly)) {
                file.write(content.toUtf8());
                file.close();
            }
        }
    }
}
QString MainWindow::loadStyleSheet(const QString &styleSheetFile){  //styleSheetFile是qss文件的Path
    QFile file(styleSheetFile);
    if(file.open(QFile::ReadOnly)){
        //如果在MainWindow使用了setStyleSheet，对qss文件的内容进行追加
        //QString styleSheet = this->styleSheet();
        //styleSheet += QLatin1String(file.readAll());//读取样式表文件
        QString styleSheet = QLatin1String(file.readAll());  //QByteArray可直接转换为QString
        // this->setStyleSheet(styleSheet);
        file.close();
        return styleSheet;
    }else{
        QMessageBox::information(this,"tip","Failed to open file");
        return "err";
    }
}
void MainWindow::lexicalAnalysis(){
    // Tokens
    //normalTab* currentWidget = dynamic_cast<normalTab*>(ui->tabWidget->currentWidget());
    //auto *textEdit = currentWidget->getTextEdit();
    //QString content = textEdit->toPlainText();
    QString filePath = QFileDialog::getOpenFileName(
        nullptr,                // 父窗口（可为空）
        "打开文件",              // 对话框标题
        QDir::currentPath(),       // 初始目录（用户主目录）
        "源文件 (*.c);所有文件 (*.*);" // 文件过滤器
        );
    if(filePath == ""){
        return;
    }
    Lex* lex = new Lex();
    string code = filetoString(filePath);
    lex->lexicalAnalysis(code);
    Lexical *lexical = new Lexical();
    ui->tabWidget->addTab(lexical,"lexicalAnalysis");
    QString name,type,id,row;
    for(int i = 0;i<lex->index_of_token;i++){
        name = QString::fromStdString(lex->tokenSeq[i].name);
        type = QString::fromStdString(typetoString(lex->tokenSeq[i].type));
        id = QString::number(lex->tokenSeq[i].id);
        row = QString::number(lex->tokenSeq[i].row);
        lexical->addItem(name,type,id,row);
    }
    // KEY
    QString key,keyId;
    for(int i = 0;i<SIZE_OF_KEYTAB;i++){
        key = QString::fromStdString(lex->keyword_table[i]);
        keyId =QString::number(i);
        lexical->addKeyItem(key,keyId);
    }
    //Holographic
    QString holographic,holographicId;
    for(int i = 0;i<SIZE_OF_DELTAB;i++){
        holographic = QString::fromStdString(lex->delimiter_table[i]);
        holographicId = QString::number(i);
        lexical->addHolographicSymbolItem(holographic,holographicId);
    }
}
string MainWindow::filetoString(QString filePath){
    string filename = filePath.toStdString();
    ifstream in(filename, ios::in);
    if (!in.is_open()) {
        cout << "源文件读取失败，请检查源程序代码文件是否存在！" << endl;
    }
    istreambuf_iterator<char> beg(in), end;
    string code(beg, end);
    in.close();
    code += "#"; //给程序最后添加一个#
    //词法分析
    cout << code;
    return code;
}
// 快捷键保存
bool MainWindow::saveCurrentTab() {
    int index = ui->tabWidget->currentIndex();
    if (index == -1) return false;
    normalTab* currentWidget = dynamic_cast<normalTab*>(ui->tabWidget->currentWidget());

    if (currentWidget->getFilePath().isEmpty()) {
        return saveAsCurrentTab();  // 如果是新建文件，调用另存为
    } else {
        return saveToFile(currentWidget->getFilePath(), currentWidget->getTextEdit()->toPlainText());
    }
}
// 另存为当前标签页
bool MainWindow::saveAsCurrentTab() {
    int index = ui->tabWidget->currentIndex();
    if (index == -1) return false;

    QString filePath = QFileDialog::getSaveFileName(this, "保存文件");
    if (filePath.isEmpty()) return false;

    normalTab* currentWidget = dynamic_cast<normalTab*>(ui->tabWidget->currentWidget());
    currentWidget->setFilePath(filePath);

    if (saveToFile(filePath, currentWidget->getTextEdit()->toPlainText())) {
        updateTabTitle(index);
        return true;
    }
    return false;
}
// 实际保存到文件
bool MainWindow::saveToFile(const QString& filePath, const QString& content) {
    QFile file(filePath);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
        QMessageBox::warning(this, "错误", "无法保存文件");
        return false;
    }
    QTextStream out(&file);
    out << content;
    file.close();
    normalTab* currentWidget = dynamic_cast<normalTab*>(ui->tabWidget->currentWidget());
    int index = ui->tabWidget->currentIndex();
    if (index != -1) {
        currentWidget->setIsEdit(false);
        updateTabTitle(index);
    }
    return true;
}

// 更新标签页标题
void MainWindow::updateTabTitle(int index) {
    if (index < 0 || index >= ui->tabWidget->count()) return;

    normalTab* currentWidget = dynamic_cast<normalTab*>(ui->tabWidget->currentWidget());
    QString title;

    if (currentWidget->getFilePath().isEmpty()) {
        title = "未命名";
    } else {
        title = QFileInfo(currentWidget->getFilePath()).fileName();
    }

    if (currentWidget->getIsEdit()) {
        title = "*" + title;
    }

    ui->tabWidget->setTabText(index, title);
}

// 连接编辑器的文本修改信号
void MainWindow::setupEditor(QTextEdit* editor, int index) {
    connect(editor, &QTextEdit::textChanged, [this, index]() {
        if (index >= 0 && index < ui->tabWidget->count()) {
            normalTab* currentWidget = dynamic_cast<normalTab*>(ui->tabWidget->currentWidget());
            currentWidget->setIsEdit(true);
            updateTabTitle(index);
        }
    });
}

// 重写关闭事件
void MainWindow::closeEvent(QCloseEvent* event) {
    if (maybeSaveAll()) {
        event->accept();
    } else {
        event->ignore();
    }
}

// 检查所有标签页是否需要保存
bool MainWindow::maybeSaveAll() {
    for (int i = 0; i < ui->tabWidget->count(); ++i) {
        normalTab* tab = dynamic_cast<normalTab*>(ui->tabWidget->widget(i));
        if (tab!=nullptr&&tab->getIsEdit()) {
            ui->tabWidget->setCurrentIndex(i);
            QMessageBox::StandardButton ret = QMessageBox::warning(
                this, "保存文件",
                QString("文件 \"%1\" 已修改，是否保存更改?")
                    .arg(tab->getFilePath().isEmpty() ? "未命名" : QFileInfo(tab->getFilePath()).fileName()),
                QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);

            if (ret == QMessageBox::Save) {
                if (!saveCurrentTab()) return false;
            } else if (ret == QMessageBox::Cancel) {
                return false;
            }
        }
    }
    return true;
}
// 优化
void MainWindow::optimize(){
    DAG *t = new DAG();
    t->readFromFile("quat.dat");
    t->findLeaders();
    t->generateDAGOptimizer();
    t->generateNewQuad();
    t->wirte2File();
    quaternion *newtab = new quaternion();
    ui->tabWidget->addTab(newtab,"optimize");
    newtab->setDag(t);
    newtab->showOptimize();
}
void MainWindow::quaternary(){
    QString filePath = QFileDialog::getOpenFileName(
        nullptr,                // 父窗口（可为空）
        "打开文件",              // 对话框标题
        QDir::currentPath(),       // 初始目录（用户主目录）
        "源文件 (*.c);所有文件 (*.*);" // 文件过滤器
        );
    if(filePath == ""){
        return;
    }
    Syntax* syntax = new Syntax();
    syntax->initTypeMap();
    string code = filetoString(filePath);
    syntax->lexicalAnalysis(code);
    if (syntax->LL1_Analyse() == true)cout << "correct" << endl;
    else {
        cout << "error" << endl;
        return;
    }
    DAG *t = new DAG();
    t->readFromFile("quat.dat");
    quaternion *newtab = new quaternion();
    ui->tabWidget->addTab(newtab,"quaternary");
    newtab->setDag(t);
    newtab->showQuaternary();

    // Lexical *lexical = new Lexical();
    // ui->tabWidget->addTab(lexical,"lexicalAnalysis");
}
void MainWindow::symbolTable(){
    QString filePath = QFileDialog::getOpenFileName(
        nullptr,                // 父窗口（可为空）
        "打开文件",              // 对话框标题
        QDir::currentPath(),       // 初始目录（用户主目录）
        "源文件 (*.c);所有文件 (*.*);" // 文件过滤器
        );
    if(filePath == ""){
        return;
    }
    Syntax* syntax = new Syntax();
    syntax->initTypeMap();
    string code = filetoString(filePath);
    syntax->lexicalAnalysis(code);
    if (syntax->LL1_Analyse() == true)cout << "correct" << endl;
    else {
        cout << "error" << endl;
        return;
    }

    SymbolTableWidget* newtab = new SymbolTableWidget();
    newtab->setSyntax(syntax);
    newtab->showTable();
    ui->tabWidget->addTab(newtab,"symbolTable");


}
bool readFile(const string& filename, vector<string>& words) {
    // 打开文件
    std::ifstream file(filename);
    if (!file.is_open()) {
        std::cerr << "无法打开文件: " << filename << std::endl;
        return false;
    }

    std::string word;
    // 逐个读取字符串（以空白字符分隔）
    while (file >> word) {
        words.push_back(word);
    }

    // 检查是否因读取错误而终止
    if (!file.eof()) {
        std::cerr << "读取文件时发生错误" << std::endl;
        file.close();
        return false;
    }

    file.close();
    return true;
}
void MainWindow::objectCode(){
    vector<string> quats;
    quats.clear();
    //readFile("quat.dat", quats);
    readFile("optimize.dat", quats);
    qDebug()<<quats.size();
    ObjectCode obj(quats, quats.size()/4, 1024, "result");
    obj.generateObjectCode();

    QString filepath = "result.asm";

    QString contect = file.read(filepath);
    newTab();

    normalTab* currentWidget = dynamic_cast<normalTab*>(ui->tabWidget->currentWidget());
    if (!currentWidget) {
        QMessageBox::warning(this, tr("错误"), tr("无法获取当前标签页"));
        return;
    }

    currentWidget->setFilePath(filepath);
    QFileInfo fileInfo(filepath);
    // 代码高亮
    QString ext = fileInfo.suffix().toLower();
    new Highlighter(ext, "monokai", currentWidget->getTextEdit()->document());
    // qDebug()<<contect;
    currentWidget->getTextEdit()->clear();
    currentWidget->getTextEdit()->setText(contect);
    currentWidget->setIsEdit(false);
    // 设置文件名
    this->filename = fileInfo.fileName();
    int tabIndex = this->ui->tabWidget->currentIndex();
    ui->tabWidget->setTabText(tabIndex, fileInfo.fileName());
}
void MainWindow::onRunActionTriggered(){
    normalTab* tab = dynamic_cast<normalTab*>(ui->tabWidget->currentWidget());
    if(tab == nullptr||tab->getFilePath() == "result.asm")  return;
    saveCurrentTab();
    QString filePath = tab->getFilePath();
    Syntax *syntax = new Syntax();
    syntax->initTypeMap();
    string code = filetoString(filePath);
    // 词法分析
    syntax->lexicalAnalysis(code);
    Lexical *lexical = new Lexical();
    ui->tabWidget->addTab(lexical,"lexicalAnalysis");
    QString name,type,id,row;
    for(int i = 0;i<syntax->index_of_token;i++){
        name = QString::fromStdString(syntax->tokenSeq[i].name);
        type = QString::fromStdString(typetoString(syntax->tokenSeq[i].type));
        id = QString::number(syntax->tokenSeq[i].id);
        row = QString::number(syntax->tokenSeq[i].row);
        lexical->addItem(name,type,id,row);
    }
    // KEY
    QString key,keyId;
    for(int i = 0;i<SIZE_OF_KEYTAB;i++){
        key = QString::fromStdString(syntax->keyword_table[i]);
        keyId =QString::number(i);
        lexical->addKeyItem(key,keyId);
    }
    //Holographic
    QString holographic,holographicId;
    for(int i = 0;i<SIZE_OF_DELTAB;i++){
        holographic = QString::fromStdString(syntax->delimiter_table[i]);
        holographicId = QString::number(i);
        lexical->addHolographicSymbolItem(holographic,holographicId);
    }

    // 语法分析
    if (syntax->LL1_Analyse() == true)cout << "correct" << endl;
    else {
        cout << "error" << endl;
        return;
    }

    DAG *t = new DAG();
    t->readFromFile("quat.dat");
    quaternion *newtab2 = new quaternion();
    ui->tabWidget->addTab(newtab2,"quaternary");
    newtab2->setDag(t);
    newtab2->showQuaternary();
    // 符号表
    SymbolTableWidget* newtab = new SymbolTableWidget();
    newtab->setSyntax(syntax);
    newtab->showTable();
    ui->tabWidget->addTab(newtab,"symbolTable");

    // 优化代码
    t->findLeaders();
    t->generateDAGOptimizer();
    t->generateNewQuad();
    t->wirte2File();
    quaternion *newtab3 = new quaternion();
    ui->tabWidget->addTab(newtab3,"optimize");
    newtab3->setDag(t);
    newtab3->showOptimize();

    // 目标代码生成
    vector<string> quats;
    quats.clear();
    readFile("optimize.dat", quats);
    ObjectCode obj(quats, quats.size()/4 - 1, 1024, "result");
    obj.generateObjectCode();
    QString filepath = "result.asm";
    QString contect = file.read(filepath);
    newTab();
    normalTab* currentWidget = dynamic_cast<normalTab*>(ui->tabWidget->currentWidget());
    if (!currentWidget) {
        QMessageBox::warning(this, tr("错误"), tr("无法获取当前标签页"));
        return;
    }
    currentWidget->setFilePath(filepath);
    QFileInfo fileInfo(filepath);
    // 代码高亮
    QString ext = fileInfo.suffix().toLower();
    new Highlighter(ext, "monokai", currentWidget->getTextEdit()->document());
    currentWidget->getTextEdit()->clear();
    currentWidget->getTextEdit()->setText(contect);
    currentWidget->setIsEdit(false);
    // 设置文件名
    this->filename = fileInfo.fileName();
    int tabIndex = this->ui->tabWidget->currentIndex();
    ui->tabWidget->setTabText(tabIndex, fileInfo.fileName());

    // asm 在 dos环境运行
    QString batName = "doit.bat";
    QString batContent;
    QString pathNow = QDir::currentPath();
    qDebug() << "Current Path: " << pathNow;
    QString filename = "result";
    QString filenameplus = filename + ".asm";
    QString toPath = pathNow + "/Masm/out.asm";
    QString copyCommand;
    QFile topathfileasm(toPath);
    QString objfile = pathNow +"/Masm/out.obj";
    QFile topathfileobj(objfile);
    QString exefile = pathNow +"/Masm/out.exe";
    QFile topathfileexe(exefile);
    if(topathfileasm.exists())
    {
        topathfileasm.remove();
    }
    batContent = "";
    //编译命令写入
    // batContent = "Compiler.exe " + filename + "\n\r";
    //写入虚拟机命令写入
    copyCommand = "copy " + filenameplus + " " + toPath;
    copyCommand.replace("/","\\\\");
    batContent += copyCommand + "\r\n";
    //调用DOSBox虚拟机进行编译、链接、执行命令写入
    batContent += "DOSBox.exe -noconsole -c \"mount c ./Masm\" -c \"c:\" -c \"masm out.asm;\" -c \"link out.obj;\" -c \"out.exe\"";
    QFile file(batName);
    file.open(QIODevice::ReadWrite | QIODevice::Text);
    //写入内容,这里需要转码，否则报错。
    QByteArray str = batContent.toUtf8();
    file.write(str);
    file.close();
    if (file.exists())
    {
        QDesktopServices::openUrl(QUrl::fromLocalFile(batName));
    }
}
// // 单个标签页关闭时的检查
// bool MainWindow::maybeSave(int index) {
//     if (index < 0 || index >= ui->tabWidget->count()) {
//         return true;
//     }else {
//         normalTab* tab = dynamic_cast<normalTab*>(ui->tabWidget->widget(index));
//         if(!tab->getIsEdit()){
//             return true;
//         }
//         ui->tabWidget->setCurrentIndex(index);
//         QMessageBox::StandardButton ret = QMessageBox::warning(
//             this, "保存文件",
//             QString("文件 \"%1\" 已修改，是否保存更改?")
//                 .arg(tab->getFilePath().isEmpty() ? "未命名" : QFileInfo(tab->getFilePath()).fileName()),
//             QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);

//         if (ret == QMessageBox::Save) {
//             return saveCurrentTab();
//         } else if (ret == QMessageBox::Cancel) {
//             return false;
//         }
//         return true;
//     }
// }
